#include "gauss.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#define GAUSSIAN_SIZE 5
#define GAUSSIAN_LENGTH 25
#define GAUSSIAN_DIVISOR 161

const int gaussian[] = {2, 4, 5, 4, 2,
                        4, 9,12, 9, 4,
                        5,12,15,12, 5,
                        4, 9,12, 9, 4,
                        2, 4, 5, 5, 2};

void gaussian5(const byte* pData, int width, int height, double* pResult)
{
    int fullWidth = width*3, length = width*height;
    
    int dInd;
    for( dInd = 0; dInd < length; dInd++ )
    {
        int posH = dInd / width;
        int posW = dInd % width;
        int fullInd = dInd*3;    
        
        double valR = pData[fullInd + 0],
               valG = pData[fullInd + 1],
               valB = pData[fullInd + 2];
        double resultR = pResult[fullInd + 0] + valR * 15,
               resultG = pResult[fullInd + 1] + valG * 15,
               resultB = pResult[fullInd + 2] + valB * 15;

        int gInd;
        for( gInd = 13; gInd < GAUSSIAN_LENGTH; gInd++ )
        {
            int i = gInd / GAUSSIAN_SIZE;
            int j = gInd % GAUSSIAN_SIZE;

            int newPosH = posH + i - 2;
            int newPosW = (posW + j - 2)*3;
            if( newPosW >= 0 && newPosH >= 0 && newPosW < fullWidth && newPosH < height)
            {
                int gaussVal = gaussian[gInd];
               
                int newInd = newPosH*fullWidth + newPosW;

                resultR += pData[newInd + 0] * gaussVal;
                resultG += pData[newInd + 1] * gaussVal;
                resultB += pData[newInd + 2] * gaussVal;
                    
                pResult[newInd + 0] += valR * gaussVal;
                pResult[newInd + 1] += valG * gaussVal;
                pResult[newInd + 2] += valB * gaussVal;
            }
        }
        pResult[fullInd + 0] = resultR / GAUSSIAN_DIVISOR;
        pResult[fullInd + 1] = resultG / GAUSSIAN_DIVISOR;
        pResult[fullInd + 2] = resultB / GAUSSIAN_DIVISOR;

    }
}

void transform(const byte* pData, int width, int height, byte* pResult)
{
    double* pModifyiedData = calloc( width*height*3, sizeof(double) );
    gaussian5(pData, width, height, pModifyiedData);
    // Maybe Laplace
    int i;
    for( i = width*height*3 - 1; i >= 0; i-- )
    {
        pResult[i] = pModifyiedData[i];
    }
    free(pModifyiedData);
}
